/******************************************************************************* * Copyright (c) 2012-2015 INRIA. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Damien Dosimont <damien.dosimont@imag.fr> * Youenn Corre <youenn.corret@inria.fr> ******************************************************************************/ package fr.inria.soctrace.tools.ocelotl.ui.snapshot; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.SWTGraphics; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.ImageLoader; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.wb.swt.SWTResourceManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fr.inria.lpaggreg.quality.DLPQuality; import fr.inria.soctrace.tools.ocelotl.core.constants.OcelotlConstants; import fr.inria.soctrace.tools.ocelotl.core.utils.FilenameValidator; import fr.inria.soctrace.tools.ocelotl.ui.views.OcelotlView; import fr.inria.soctrace.tools.ocelotl.ui.views.QualityView; import fr.inria.soctrace.tools.ocelotl.ui.views.TimeAxisView; import fr.inria.soctrace.tools.ocelotl.ui.views.timelineview.AggregatedView; import fr.inria.soctrace.tools.ocelotl.ui.views.timelineview.TimeLineViewManager; import fr.inria.soctrace.tools.ocelotl.ui.views.timelineview.TimeLineViewWrapper; import fr.inria.soctrace.tools.ocelotl.ui.views.unitAxisView.UnitAxisView; import fr.inria.soctrace.tools.ocelotl.ui.views.unitAxisView.UnitAxisViewManager; import fr.inria.soctrace.tools.ocelotl.ui.views.unitAxisView.UnitAxisViewWrapper; public class Snapshot { private static final Logger logger = LoggerFactory.getLogger(Snapshot.class); // Directory where all the snapshots are saved private String snapshotDirectory; private OcelotlView theView; public Snapshot(String directory, OcelotlView aView) { theView = aView; snapshotDirectory = theView.getOcelotlParameters().getOcelotlSettings().getSnapShotDirectory(); } public String getSnapshotDirectory() { return snapshotDirectory; } /** * Call all the methods that create a snapshot of the current state of Ocelotl */ public void takeSnapShot() { // Create and set directory String currentDirPath = createDirectory(); // Take a snapshot of the statistics saveStatistics(currentDirPath); // Save the currently displayed diagram as an image snapShotDiagram(currentDirPath); // Save the currently displayed quality curves as an image snapShotQualityCurve(currentDirPath); // Save the currently displayed axes snapShotAxes(currentDirPath); // Save the current parameters in a text file saveConfig(currentDirPath); // Save the current parameter P values (+ gain/loss) in a .csv saveParameterValues(currentDirPath); // Create a symbolic link to the trace file // createSymLink(currentDirPath); } /** * Create a png image of the diagram * @param dirPath */ public void snapShotDiagram(String dirPath) { Shell dialogMainView = new Shell(Display.getDefault()); dialogMainView.setSize(theView.getOcelotlParameters().getOcelotlSettings().getSnapshotXResolution() + 2, theView.getOcelotlParameters().getOcelotlSettings().getSnapshotYResolution() + 2); // Init drawing display zone Composite compositeMainView = new Composite(dialogMainView, SWT.BORDER); compositeMainView.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND)); // Make sure we remove the title bar from the size in order to // display it fully compositeMainView.setSize(dialogMainView.getSize().x, dialogMainView.getSize().y); compositeMainView.setLayout(new FillLayout()); TimeLineViewWrapper mainViewWrapper = new TimeLineViewWrapper(theView); mainViewWrapper.init(compositeMainView); TimeLineViewManager mainViewManager = new TimeLineViewManager(theView); AggregatedView mainView = (AggregatedView) mainViewManager.create(); mainView.setMainView(false); mainViewWrapper.setView(mainView); mainView.createDiagram(theView.getCore().getLpaggregManager(), theView.getOcelotlParameters().getTimeRegion(), theView.getCore().getVisuOperator()); mainView.getSelectFigure().draw(theView.getTimeRegion(), -1, -1); mainView.setSelectTime(((AggregatedView) theView.getTimeLineView()).getSelectTime()); mainView.setCurrentlySelectedNode(((AggregatedView) theView.getTimeLineView()).getCurrentlySelectedNode()); mainView.drawSelection(); compositeMainView.layout(); createSnapshotFor(mainView.getRoot(), dirPath + "/diagram.png"); } /** * Create a png image of the quality curve * @param dirPath */ public void snapShotQualityCurve(String dirPath) { Shell dialogQualityView = new Shell(Display.getDefault()); dialogQualityView.setSize(theView.getOcelotlParameters().getOcelotlSettings().getQualCurveXResolution() + 2, theView.getOcelotlParameters().getOcelotlSettings().getQualCurveYResolution() + 2); // Init drawing display zone Composite compositeQualityView = new Composite(dialogQualityView, SWT.BORDER); compositeQualityView.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND)); compositeQualityView.setFont(SWTResourceManager.getFont("Cantarell", 11, SWT.NORMAL)); compositeQualityView.setSize(dialogQualityView.getSize().x, dialogQualityView.getSize().y); compositeQualityView.setLayout(new FillLayout()); QualityView aQualityView = new QualityView(theView); aQualityView.initDiagram(compositeQualityView); aQualityView.createDiagram(); compositeQualityView.layout(); createSnapshotFor(aQualityView.getRoot(), dirPath + "/curves.png"); } /** * Create png images of the axes * @param dirPath */ public void snapShotAxes(String dirPath) { // Time axis snapshot Shell dialogTimeAxis = new Shell(Display.getDefault()); dialogTimeAxis.setSize(theView.getOcelotlParameters().getOcelotlSettings().getSnapshotXResolution() + 2, theView.getOcelotlParameters().getOcelotlSettings().getxAxisYResolution() + 2); // Init drawing display zone Composite compositeOverview = new Composite(dialogTimeAxis, SWT.BORDER); compositeOverview.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND)); compositeOverview.setSize(dialogTimeAxis.getSize().x, dialogTimeAxis.getSize().y); compositeOverview.setLayout(new FillLayout()); TimeAxisView aTimeAxisView = new TimeAxisView(theView); aTimeAxisView.initDiagram(compositeOverview); // If the selected time region is identical to the whole displayed time // region if (theView.getOcelotlParameters().getTimeRegion().compareTimeRegion(theView.getTimeRegion())) // Do not draw the selection aTimeAxisView.createDiagram(theView.getOcelotlParameters().getTimeRegion()); else aTimeAxisView.createDiagram(theView.getOcelotlParameters().getTimeRegion(), theView.getTimeRegion(), false); compositeOverview.layout(); createSnapshotFor(aTimeAxisView.getRoot(), dirPath + "/XAxis.png"); // Y axis snapshot Shell dialogUnitAxis = new Shell(Display.getDefault()); dialogUnitAxis.setSize(theView.getOcelotlParameters().getOcelotlSettings().getyAxisXResolution() + 2, theView.getOcelotlParameters().getOcelotlSettings().getSnapshotYResolution() + 2); // Init drawing display zone Composite compositeUnitAxis = new Composite(dialogUnitAxis, SWT.BORDER); compositeUnitAxis.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND)); compositeUnitAxis.setSize(dialogUnitAxis.getSize().x, dialogUnitAxis.getSize().y); compositeUnitAxis.setLayout(new FillLayout()); UnitAxisViewWrapper aUnitAxisWrapper = new UnitAxisViewWrapper(theView); aUnitAxisWrapper.init(compositeUnitAxis); UnitAxisViewManager aUnitAxisManager = new UnitAxisViewManager(theView); UnitAxisView unitAxisView = aUnitAxisManager.create(); aUnitAxisWrapper.setView(unitAxisView); unitAxisView.createDiagram(theView.getCore().getVisuOperator()); unitAxisView.select(theView.getUnitAxisView().getOriginY(), theView.getUnitAxisView().getCornerY(), true); compositeUnitAxis.layout(); createSnapshotFor(unitAxisView.getRoot(), dirPath + "/YAxis.png"); // Reupdate with the current timeline view in order to reset back to // correct selection values theView.getTimeLineView().drawSelection(); } /** * Save the actual configuration (trace name, number of slice , start and * end timestamps, used operators, parameter, gain and loss) */ public String saveConfig(String aDirPath) { String config = getParameters(); PrintWriter writer; try { writer = new PrintWriter(aDirPath + "/parameters.txt", "UTF-8"); writer.print(config); // Close the fd writer.flush(); writer.close(); } catch (FileNotFoundException | UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return config; } /** * Format the parameters as a string * * @return the formatted string */ public String getParameters() { List<DLPQuality> qualities = theView.getCore().getLpaggregManager().getQualities(); List<Double> parameters = theView.getCore().getLpaggregManager().getParameters(); double gain = 0; double loss = 0; // Look for the gain and loss value for (int i = 0; i < parameters.size(); i++) { if (theView.getOcelotlParameters().getParameter() <= parameters.get(i)) { gain = qualities.get(i).getGain(); loss = qualities.get(i).getLoss(); break; } } StringBuffer output = new StringBuffer(); output.append("Trace name: "); output.append(theView.getOcelotlParameters().getTrace().getAlias()); output.append("\nNumber of slices: "); output.append(theView.getOcelotlParameters().getTimeSlicesNumber()); output.append("\nDisplayed Start timestamp: "); output.append(theView.getTextDisplayedStart().getText()); output.append("\nDisplayed End timestamp: "); output.append(theView.getTextDisplayedEnd().getText()); output.append("\nSelected Start timestamp: "); output.append(theView.getTextTimestampStart().getText()); output.append("\nSelected End timestamp: "); output.append(theView.getTextTimestampEnd().getText()); output.append("\nMetric type: "); output.append(theView.getOcelotlParameters().getMicroModelType()); output.append("\nAggregation Operator: "); output.append(theView.getOcelotlParameters().getDataAggOperator()); output.append("\nVisualization Operator: "); output.append(theView.getOcelotlParameters().getVisuOperator()); output.append("\nStatistics Operator: "); output.append(theView.getOcelotlParameters().getStatOperator()); if (theView.getCore().getVisuOperator().getMaxValue() > 0) { output.append("\nMax Amplitude Value: "); output.append(theView.getCore().getVisuOperator().getMaxValue()); } output.append("\nParameter: "); output.append(theView.getOcelotlParameters().getParameter()); output.append("\nGain: "); output.append(gain); output.append(" - Loss: "); output.append(loss); return output.toString(); } /** * Create a unique directory for the current snapshot */ public String createDirectory() { String dirName = ""; File dir = new File(snapshotDirectory); // Check if the general directory exists if (!dir.exists()) { logger.debug("Snapshot directory (" + snapshotDirectory + ") does not exist and will be created now."); // Create the general snapshot directory if (!dir.mkdirs()) { logger.error("Failed to create cache directory: " + snapshotDirectory + "."); } } Date aDate = new Date(System.currentTimeMillis()); String convertedDate = new SimpleDateFormat("dd-MM-yyyy_HHmmss_z").format(aDate); String fileName = theView.getOcelotlParameters().getTrace().getAlias() + "_" + convertedDate; fileName = FilenameValidator.checkNameValidity(fileName); dirName = snapshotDirectory + "/" + fileName; // Create the specific snapshot directory dir = new File(dirName); if (!dir.mkdirs()) { logger.error("Failed to create cache directory: " + dirName + "."); } return dirName; } /** * Save the the current parameter P values (+ gain/loss) in a .csv */ public void saveParameterValues(String aDirPath) { StringBuffer output = new StringBuffer(); List<DLPQuality> qualities = theView.getCore().getLpaggregManager().getQualities(); List<Double> parameters = theView.getCore().getLpaggregManager().getParameters(); // CSV header output.append("PARAMETER" + OcelotlConstants.CSVDelimiter + "GAIN" + OcelotlConstants.CSVDelimiter + "LOSS\n"); // Get all parameters, gain and loss values for (int i = 0; i < parameters.size(); i++) { output.append(parameters.get(i) + OcelotlConstants.CSVDelimiter); output.append(qualities.get(i).getGain() + OcelotlConstants.CSVDelimiter); output.append(qualities.get(i).getLoss() + "\n"); } // Save into a file PrintWriter writer; try { writer = new PrintWriter(aDirPath + "/parameterPValues.csv", "UTF-8"); writer.print(output.toString()); // Close the fd writer.flush(); writer.close(); } catch (FileNotFoundException | UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void saveStatistics(String aDirPath) { String stats = theView.getStatView().getStatDataToCSV(); if (stats.isEmpty()) { logger.debug("Failed to convert statisitics in CSV format."); return; } // Save into a file PrintWriter writer; try { writer = new PrintWriter(aDirPath + "/statistics.csv", "UTF-8"); writer.print(stats); // Close the fd writer.flush(); writer.close(); } catch (FileNotFoundException | UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Create a symbolic link to the trace file * @param aDirPath */ public void createSymLink(String aDirPath) { Process p; try { p = Runtime.getRuntime().exec("ln -s " + aDirPath + "/A\\ Link\\ to\\ the\\ trace"); p.waitFor(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Create an image from the Figure given in argument * * @param figure * Figure from which the image is created * @param fileName * Path where to save the image */ public void createSnapshotFor(Figure figure, String fileName) { byte[] imageBytes = createImage(figure, SWT.IMAGE_PNG); if (imageBytes == null) { logger.debug("Image generation failed: snapshot image will not be created"); return; } try { FileOutputStream out = new FileOutputStream(fileName); out.write(imageBytes); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } /** * Generate the image * * @param figure * Figure from which the image is created * @param format * format of the generated image * @return an array of bytes corresponding to an image */ private byte[] createImage(Figure figure, int format) { Device device = Display.getCurrent(); Rectangle r = figure.getBounds(); if (r.width <= 0 || r.height <= 0) { logger.debug("Size of figure is 0: stopping generation"); return null; } ByteArrayOutputStream result = new ByteArrayOutputStream(); Image image = null; GC gc = null; Graphics g = null; try { image = new Image(device, r.width, r.height); gc = new GC(image); g = new SWTGraphics(gc); g.translate(r.x * -1, r.y * -1); figure.paint(g); ImageLoader imageLoader = new ImageLoader(); imageLoader.data = new ImageData[] { image.getImageData() }; imageLoader.save(result, format); } catch (Exception e) { e.printStackTrace(); } finally { if (g != null) { g.dispose(); } if (gc != null) { gc.dispose(); } if (image != null) { image.dispose(); } } return result.toByteArray(); } /** * Check that the snapshot directory is a valid one, i.e. does it exist and can * it be written in * * @param snapDirectory * path to the new snap directory * @return true if valid, false otherwise */ public boolean checkSnapDirectoryValidity(String snapDirectory) { // Check the existence of the cache directory File dir = new File(snapDirectory); if (!dir.exists()) { logger.debug("Snapshot directory (" + snapDirectory + ") does not exist and will be created now."); // Create the directory if (!dir.mkdirs()) { logger.error("Failed to create snapshot directory: " + snapDirectory + "."); if (this.snapshotDirectory.isEmpty()) { logger.error("The current snapshot directory is still: " + this.snapshotDirectory); } return false; } } // Check that we have at least the reading rights if (!dir.canWrite()) { logger.error("The application does not have the rights to write in the given directory: " + snapDirectory + "."); if (this.snapshotDirectory.isEmpty()) { logger.error("The cache will be turned off."); } else { logger.error("The current cache directory is still: " + this.snapshotDirectory); } return false; } return true; } }